#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TOTAL_CHARS 1000
#define TOTAL_WORDS 100
#define FILE_NAME "shakespe.txt"

int palindrome_word(char *); // verifica se palavra é palindromo
int palindrome_phrase(char [][25], int); // verifica se frase é palindromo
void clean_tokens(char [][25], int *); // limpa vetor de tokens
int bline(char **, char *); // Retorna 1 linha do bloco
int fsize(char *); // Retorna o tamanho do arquivo lido

int main (int argc, char *argv[]) {

  /*
    totalw - total de palavras palindromes
    totalp - total de frases palindromes
    fname - nome do arquivo
    fsizevar - variável que guarda tamanho do arquivo
  */
  int totalw = 0, totalp = 0, fsizevar;
  char fname[30];
  
  strcpy(fname, (argc > 1 && argv[1] != NULL) ? argv[1] : FILE_NAME); // Seta o nome do arquivo dependendo dos argumentos

  /*
    tokens - array de tokens, que guardaram as palavras de uma frase
    line - string com a linha do bloco (é incrementada a cada loop)
    ntokens - número de tokens correntes
    text - guardará o texto do arquivo
  */
  char tokens[TOTAL_WORDS][25], line[TOTAL_CHARS];
  int ntokens = 0, i;
  
  FILE *f;
  char *text;

  fsizevar = fsize(fname);
  text = (char*) calloc(fsizevar+1, sizeof(char));

  // Lê o texto que está no arquivo
  if (!(f = fopen(fname, "r")) || !fread(text, sizeof(char), fsizevar, f))
    exit(1);
  
  fclose(f);

  bline(&text, line); // Recupera a primeira linha do texto

  do {  

    char *token, *rest, *ptr = line;

    // Separa a linha do texto em tokens (palavras) utilizando a função strtok_r
    while((token = strtok_r(ptr, " ,.-()", &rest))) {
      strcpy(tokens[ntokens], token);
      ntokens++;
      ptr = rest;    
    }

    // Percorre o array de tokens verificando se é palindromo ou não
    for(i=0 ; i<ntokens ; i++)
      if(palindrome_word(tokens[i]))
        totalw++;
      
    // Verifica se o array de tokens é palindromo
    if(palindrome_phrase(tokens, ntokens))
      totalp++;
    
    // Limpa o array tokens para a proxima iteração
    clean_tokens(tokens, &ntokens);

  } while(bline(&text, line)); // Percorre todas as linhas do texto até acabar

  printf("Total de palavras palindromes: %d\n", totalw);
  printf("Total de frases palindromes: %d\n", totalp);

  return 0;
}

int palindrome_word(char *str) {

  int size, i, j, palindrome = 1;

  size = strlen(str);

  if(size > 1)
    for(i=0, j=size-1; i < size ; i++, j--)
      palindrome = palindrome && (str[i] == str[j]);
  else
    palindrome = 0;

  return palindrome;

}

int palindrome_phrase(char tokens[][25], int n_tokens) {

  int i, j, palindrome = 1;

  if (n_tokens > 1)
    for(i=0, j=n_tokens-1; i < n_tokens ; i++, j--)
      palindrome = palindrome && (strcmp(tokens[i], tokens[j]) == 0);
  else
    palindrome = 0;

  return palindrome; 

}

void clean_tokens(char tokens[][25], int *n_tokens) {

  int i;

  for(i=0; i<40 ;i++)
    strcpy(tokens[i], "");

  *n_tokens = 0;

}

int bline(char **block, char *str) {

  char c, aux[TOTAL_CHARS] = "";
  int i = 0;

  c = **block, (*block)++; // Caminha com o primeiro caracter do bloco
  
  if(c != '\0') {
    while((int)c != 13 && c != '\n' && c != '\0') { // Verifica se é quebra de linha ou fim de linha (^M, \n, \0)
      if((int)c != 9)
        aux[i] = c, i++;
      else
        aux[i] = ' ', i++;
      c = **block, (*block)++; // Caminha para o próximo caracter do bloco
    }

    strcpy(str, aux);

    return 1;
  } else
    return 0;
    
}

int fsize(char *fname) {
    
  int size;
  FILE *f;
  
  // Caminha com o ponteiro até o final do arquivo, e verifica o número de bytes, que corresponde ao tamanho total
  if(!(f = fopen(fname, "r")) || fseek(f, 0, SEEK_END) || !(size = ftell(f)))
    exit(1);

  fclose(f);
  
  return size;
}
